#ifndef _SOCKET_H_
#define _SOCKET_H_
#include <list>
#include <arpa/inet.h>  // 本地字节序与网络字节序的转换
#include <netinet/in.h> // ipv4结构体
#include <pthread.h>
#include <atomic>
#include <sys/epoll.h>

#include <atomic>
#include <time.h>
#include <map>
#include <semaphore.h>  //信号量
#include "macro.h"
// d:对象    p: 指针
typedef struct listenting_s  listenting_d,*listenting_p;
typedef struct connection_s connection_d,*connection_p;
class _socket;
typedef void (_socket::*event_handler_pt)(connection_p c);  //定义成员函数指针
//监听套接字的结构
struct listenting_s
{
    int fd;     //socket句柄
    int port;   // 监听的端口号
    connection_p connection;    //所属的连接池里的某一指针
};

struct message_head{
    connection_p con_p; //记录这条条消息是哪个连接接受的
    int iCurrSequence;  //记录接收数据当时的这个值，用于到时候处理数据前判断，该连接还在不在
};
typedef struct message_head  message_head_d;

struct package_head_s{
    unsigned short pkg_body_len;    // 包头长度，用于后续的接收---字节数
    unsigned short pkg_type;    //由于自定义应用层，那么就需要判断类型，决定之后执行什么业务逻辑函数
    int crc32;                  //用于crc校验
};
typedef  struct package_head_s package_head_d;

//所有TCP连接的结构体信息
struct connection_s{
    connection_s();
    ~connection_s();
    void get_one_to_init();     //当从连接池子里拿取时，做一些初始化工作
    void put_one_to_free();     //当连接失效后，回收到空闲连接的一些释放工作

    listenting_p listen;    //监听套接字需要的
    std::atomic<int> icurrentsequence;  //当分配一个连接，或关闭一个连接，那么这个值就++  通过该值判断当前连接的有效性

    int fd; //连接句柄
    struct sockaddr_in opposite_addr;   //对方的地址

    //读写事件处理的回调函数
    event_handler_pt event_read_handler;    //对于监听套接字来说，那么就是接收连接 对于TCP客户端来说，就是读取数据
    event_handler_pt event_write_handler;   // 监听套接字没有写事件，对于TCP客户端来说，在发送缓冲区满了之后，通过时间触发发送
    
    //回收·队列
    time_t add_recycle_time;    // 加入回收队列的时间

    //上次ping的时间
    time_t last_ping;

    //收包相关
    char  cur_stat;     //当前收包状态    采用枚举
    char  package_head[20];    //包头信息
    char * precvbuf;    //收包缓冲区
    u_int32_t precvlen; //收包长度
    char * recv_message_ptr; //整个消息的指针，能够用于释放之类的,接收到包头后，知晓了长度后new出来的，直到放入消息处理函数后置空
    std::atomic<int> wait_to_deal_received_pkgs;    //收到包，但是还没有处理的包的数量，只有真正处理完，这个数量才会--

    //发包相关,用于发送缓冲区满了，通过事件驱动完成包的发送
    char send_buf_is_full_flag;     //发送缓冲区是否满了的标志  1满了  0没满
    char * sendbuf; //  当前发送缓冲区
    u_int32_t sendlen;  // 当前发送所需长度
    char * send_message_ptr;    // 该条消息的指针，发送失败，或发送完毕后，释放掉

    //该fd积压的消息-----对端网络有问题
    std::atomic<int> wait_to_send_count;    //处理完数据后，存在需要发送数据的情况，这里记录一下数据的发送情况 


};

class _socket;  //声明一下
class thread_item_for_socket{
public:
    pthread_t handler;
    _socket * external_socket;
    thread_item_for_socket(_socket * external_socket){
        this->external_socket=external_socket;  //用于线程体能够拿到外部的类里的信息
    }

};

class _socket{
public:

    
    _socket();
    
    ~_socket();
    std::list<thread_item_for_socket *> function_threads;   //回收待释放的连接的线程  超时踢人线程  发送消息线程----不用这个了
    //多个线程item的句柄
    thread_item_for_socket * send_message_item;
    thread_item_for_socket * recycle_connection_item;
    thread_item_for_socket * kick_map_item;

    //资源初始化，释放
    void all_source_init();
    void all_source_release();

    void read_conf();   //读取配置文件
    //开启整个程序流程（没有单例类的初始化）  包括资源初始化，监听套接字创建，连接池，epoll初始化 ，监听套接字放入epoll，线程池
    void start_this_pro();      
    //结束整个流程
    void end_this_pro();

    //epoll
    int epoll_fd;   //epoll句柄
    void init_epoll();  //初始化epoll
    int change_epoll_event(int fd,uint32_t new_event,connection_p con_p);   //改变epoll_event
    struct epoll_event events[MAX_EVENTS];
    void doing_epoll_wait();    // 开始接收连接/数据-------考虑做成被不断的调用
    
    // 时间处理函数
    void accept_event_handler(connection_p con_p);  //监听套接字触发的读处理事件
    void recv_event_handler(connection_p con_p);    //接收事件处理函数
    int doing_recv(connection_p con_p); //接收数据的工具函数
    void after_recv_header_complete(connection_p con_p);    //接受完包头后，需要处理的一系列数据
    void after_recv_body_complete(connection_p con_p);  //接收完包体后的处理工作
    void write_event_handler(connection_p con_p);   //写事件处理函数

    //连接池
    
    bool init_connection_pool();    //初始化连接池
    int work_connections;       //允许的连接池大小，可能会增长
    connection_p get_one_free_con();    //从空闲连接链表里拿取一个

     //监听套接字队列
    bool init_listening_socket();   //初始化监听套接字
    std::list<listenting_p> listening_list;
    bool set_no_blocking(int fd);
    int listen_fd_num;  //监听的套接字数量   监听的端口通过配置文件读取
    void add_listening_fd_to_connection_pool(); //将监听套接字放入连接池子里，并加入epoll等待事件中
    

    //连接队列
    std::list<connection_p> all_connection;  //保存全部的连接队列
    std::list<connection_p> free_connection;    //保存空闲连接队列
    pthread_mutex_t connection_mtx;     //用于互斥连接队列，空闲队列会有元素进进出出
    std::atomic<int> total_connections_num; //当前连接数量
    std::atomic<int> free_connections_num;  //当前空闲连接数量
    bool add_connection_to_free(connection_p p);    // 添释放一个连接,直接回收
    std::atomic<int> online_clients;    //当前在线数量

    
    //待释放连接队列----延迟回收队列
    std::map<connection_p,int> is_exists;   //加入待释放队列时，判断是否存在，避免重复加入
    std::list<connection_p> recycle_connection;    //待释放连接队列
    pthread_mutex_t recycle_connection_mtx;     // 互斥回收队列
    std::atomic<int>  recycle_connection_num;   // 待回收队列的数量
    int recycle_time;   //等待多长时间回收
    bool add_con_to_recycle(connection_p con_p);//放入回收队列中去
    static void* deal_recycle_connection_thread(void * thread_item);    //处理待回收连接的线程
    std::atomic<bool> deal_recycle_running_flag;    //处理回收线程的线程标志


    //踢人时钟队列-----检测心跳包有无超时
    std::multimap<time_t,message_head_d*> kick_map;   //踢人队列
    pthread_mutex_t kick_mutex;     // 踢人队列互斥量
    void add_con_to_kick_map(connection_p con_p);   //加入踢人队列
    void delete_con_from_kick_map(message_head_d  *con);  // 移除
    // void deal_check_time_out(time_t now_time,message_head_d * con);
    std::atomic<bool> kick_map_check_thread_running_flag;   // 踢人线程运行标志
    static void* kick_map_check_timeOut_thread(void * item);   // 踢人循环检测线程
    bool is_start_kick_map;  //是否开启踢人
    int time_of_check_gap;                //间隔的检测时间
    bool is_force_to_kick;  //是否超过一定的时间就直接踢出---这种多半不会启动
    int time_of_force_kick;  // //超时强制踢出时间
    //通过与last_ping进行判断，取出来，如果超时了，那么就不再放回，然后从该map中移除，并放入待释放连接队列
    void doing_check_is_timeout(time_t now,std::list<message_head_d *> & l);   //传递的是引用，不用担心很大
    void clear_kick_map();
    void end_kick_thread();






    //发送队列
    std::list<char *> send_message_list;    //消息发送队列，由一个线程去处理
    std::atomic<int>  send_message_list_size;   //记录里面消息大小
    std::atomic<bool> send_message_thread_running_flag; //发送线程结束与否
    static void * send_message_to_client_thread(void * thread_item);    // 发送消息的线程函数
    pthread_mutex_t send_message_mutex;     // 发送队列互斥锁
    pthread_cond_t send_thread_cond;  //发送队列条件变量
    int doing_send(int fd,char*buffer,int len); //执行发送逻辑
    void move_message_to_send_list(connection_p con_p,const char *body,unsigned short body_len,unsigned short pkg_type);
    void clear_send_message_list(); //清空消息里的东西

    //线程池中数据的处理函数
    int num_of_thread;  //线程池的数量
    virtual void thread_for_deal_message(char * message);   //拿到数据后的处理函数，可以通过子类去重写


};


#endif